package com.gmscosmo.janus.util;

import com.gmscosmo.common.LoadDistributionStrategy;
import com.gmscosmo.janus.cache.IMessagesStore;
import com.gmscosmo.janus.config.JanusConfig;
import com.gmscosmo.janus.handler.JanusStreamingRabbitMqEventHandler;
import com.gmscosmo.janus.handler.JanusVideoRoomRabbitMqEventHandler;
import com.gmscosmo.janus.lock.RedissLockUtil;
import com.gmscosmo.janus.sendMessage.IMSender;
import com.gmscosmo.janus.sendMessage.WebSocketSender;
import com.gmscosmo.model.*;
import com.gmscosmo.janus.queue.RabbitmqHttpRequestUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.TimeUnit;

public abstract class JanusUtil {
    @Autowired
    JanusLogUtil janusLogUtil;
    @Lazy
    @Autowired
    JanusConfig janusConfig;
    @Autowired
    IMessagesStore messagesStore;
    @Lazy
    @Autowired
    JanusVideoRoomRabbitMqEventHandler videoRoomHandler;
    @Lazy
    @Autowired
    JanusStreamingRabbitMqEventHandler streamingHandler;
    @Autowired
    RabbitmqHttpRequestUtil rabbitmqHttpRequestUtil;
    @Autowired
    IMSender imSender;
    @Autowired
    WebSocketSender webSocketSender;

    protected static ConcurrentHashMap<Long, String> userSessionMap = new ConcurrentHashMap(16);
    protected static CopyOnWriteArraySet<String> transactionsSet = new CopyOnWriteArraySet<>();

    protected int getNodeId(int length){
        Random random = new Random();
        if (length <= 0) {
            length = 4;
        }
        int t = (int) Math.pow(10, length-1);
        int r = random.nextInt(9 * t) + t;
        return r;
    }

    /**
     * 检测配置环境，
     * 获取一个分布式或者单机janus工具类单例
     * 抽象类方法由子类改写
     * 单机版IM使用内存缓存来存储janus所需信息，如房间，参加者等
     * 分布式IM使用redis缓存来存储janus所需信息，如房间，参加者等
     *
     * @return
     */
//    @Bean(name = "JanusUtil")
//    public JanusUtil getInstance() {
//        if (janusConfig.is_distributed) {
//            return new DistributedIMJanusUtil();
//        } else {
//            return new SingleIMJanusUtil();
//        }
//    }
    public abstract boolean getIsShareStream();

    public abstract int getMaxParticipant();

    public abstract int getLoadDistributionStrategy();

    /**
     * 获取streamId，当用户已经使用rtp转发到目标服务器时，不需要再新建一个rtp转发，而直接使用该streamId进行观看。
     *
     * @param userId
     * @param host
     * @param roomId
     * @return
     */
    public Integer getStreamId(String userId, String host, Integer roomId) {
        List<Producer> producerList = getProducers(userId);
        if (producerList == null) {
            return 0;
        }
        for (Producer producer : producerList) {
            if (producer.getHost().equals(host) && producer.getRoom().equals(roomId)) {
                return producer.getStreamId();
            }
        }
        return 0;
    }
    public void handleLeaving(long session_id) {
        String userId = getUserIdBySession(session_id);
        janusLogUtil.log("处理"+userId+"离开事件",this.getClass(),JanusLogUtil.TRACE);
        if (userId != null) {
            try {
                if (isUserNodeContains(userId)) {
                    videoRoomHandler.stopMyRtpForward(userId);
                    janusLogUtil.log(userId + "暂停所有rtp转发", this.getClass(), JanusLogUtil.TRACE);
                    if(!getIsShareStream()){
                        List<Subscriber> subscribers = getSubscribers(userId);
                        for (Subscriber subscriber : subscribers) {
                            videoRoomHandler.stopOtherRtpForward(subscriber.getSubscriberFrom(),userId);
                            janusLogUtil.log(subscriber.getSubscriberFrom() + "暂停所有rtp转发", this.getClass(), JanusLogUtil.TRACE);
                        }
                        streamingHandler.destroyMyStream(userId);
                        janusLogUtil.log(userId + "暂停所有stream接收", this.getClass(), JanusLogUtil.TRACE);
                    }
                    notifyAllParticipantLeaving(userId);
                    removeUserFromNode(userId);
                    leaveRoom(userId);
                    removeEventListener(session_id);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    /**
     * 处理janus session timeout
     * 当用户未按照正常程序结束音视频聊天时，如程序闪退，崩溃等
     * 用于释放数据
     *
     * @param session_id
     */
    public void handleTimeout(long session_id) {
        String userId = getUserIdBySession(session_id);
        janusLogUtil.log("处理"+userId+"超时事件",this.getClass(),JanusLogUtil.TRACE);
        if (userId != null) {
            try {
                //如果APP遇到闪退或者强制关闭等，未按照正常流程离开房间
                if (isUserNodeContains(userId)) {
                    removeProducers(userId);
                    janusLogUtil.log("释放用户"+userId+"生产者",this.getClass(),JanusLogUtil.TRACE);
                    List<Subscriber> subscriberList = getSubscribers(userId);
                    if (subscriberList != null) {
                        for (Subscriber subscriber : subscriberList) {
                            removePort(subscriber.getAudio_port());
                            removePort(subscriber.getVideo_port());
                            removePort(subscriber.getVideo_port_2());
                            removePort(subscriber.getVideo_port_3());
                            if (subscriber.getVideo_rtcp_port() != null) {
                                removePort(subscriber.getVideo_rtcp_port());
                            }
                        }
                    }
                    removeSubscribers(userId);
                    janusLogUtil.log("销毁用户:"+userId+"所有消费者",this.getClass(),JanusLogUtil.TRACE);
                    notifyAllParticipantLeaving(userId);
                    removeUserFromNode(userId);
                    leaveRoom(userId);
                    removeEventListener(session_id);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 添加该session_id所属用户的事件监听
     *
     * @param userId
     * @param session_id
     */
    public void addEventListener(String userId, long session_id) {
        janusLogUtil.log(userId+"绑定session_id:"+session_id,this.getClass(),JanusLogUtil.TRACE);
        userSessionMap.put(session_id, userId);
    }

    /**
     * 移除该session_id所属用户的事件监听
     *
     * @param session_id
     */
    public void removeEventListener(long session_id) {
        janusLogUtil.log("移除session_id:"+session_id+"所属用户的事件监听",this.getClass(),JanusLogUtil.TRACE);
        userSessionMap.remove(session_id);
    }

    /**
     * 通过janus session_id获取用户id
     *
     * @param session_id
     * @return
     */
    public String getUserIdBySession(long session_id) {
        return userSessionMap.get(session_id);
    }

    /**
     * 添加监听事务号，只有当前服务器中有该事务号，才能消费janus返回的数据，否则会拒绝消费
     *
     * @param transaction
     */
    public void addTransaction(String transaction) {
        transactionsSet.add(transaction);
    }

    /**
     * 移除事务号，当消费完成之后可以移除事务号。
     *
     * @param transaction
     */
    public void removeTransaction(String transaction) {
        transactionsSet.remove(transaction);
    }

    /**
     * 查询该事务号是否属于当前服务器
     *
     * @param transaction
     * @return
     */
    public boolean isTransaction(String transaction) {
        return transactionsSet.contains(transaction);
    }

//    /**
//     * 发送janus 事件
//     *
//     * @param userId
//     * @param remoteEvent
//     */
//    public void sendEvent(String userId, RemoteEvent remoteEvent) {
//        asyncSender.sendEvent(userId, remoteEvent);
//    }

    /**
     * 查询用户是否存在消费
     *
     * @param userId
     * @return
     */
    public abstract Boolean isSubscribersContains(String userId);

    /**
     * 获取用户消费者列表
     *
     * @param userId
     * @return
     */
    public abstract List<Subscriber> getSubscribers(String userId);

    /**
     * 移除用户消费者
     *
     * @param userId
     */
    public abstract void removeSubscribers(String userId);

    /**
     * 更新用户消费者列表
     *
     * @param userId
     * @param subscriberList
     */
    public abstract void putSubscribers(String userId, List<Subscriber> subscriberList);

    /**
     * 更新用户消费者列表
     *
     * @param userId
     * @param subscriber
     */
    public void putSubscribers(String userId, Subscriber subscriber){
        List<Subscriber> subscriberList = isSubscribersContains(userId) ? getSubscribers(userId) : new ArrayList<>();
        subscriberList.add(subscriber);
        putSubscribers(userId, subscriberList);
        janusLogUtil.log("更新用户:"+userId+"消费者列表:"+subscriberList,this.getClass(),JanusLogUtil.TRACE);
    }

    /**
     * 查询用户是否存在生产
     *
     * @return
     */
    public abstract Boolean isProducersContains(String userId);

    /**
     * 获取用户生产者列表
     *
     * @param userId
     * @return
     */
    public abstract List<Producer> getProducers(String userId);

    /**
     * 移除用户生产者
     *
     * @param userId
     */
    public abstract void removeProducers(String userId);

    /**
     * 更新用户生产者
     */
    public abstract void putProducers(String userId, List<Producer> producerList);

    /**
     * 更新用户生产者
     */
    public void putProducers(String userId, Producer producer){
        List<Producer> producerList = isProducersContains(userId) ? getProducers(userId) : new ArrayList<>();
        producerList.add(producer);
        putProducers(userId, producerList);
        janusLogUtil.log("更新用户:"+userId+"生产者列表:"+producerList,this.getClass(),JanusLogUtil.TRACE);
    }

    /**
     * 查询用户是否任在某一个节点
     *
     * @return
     */
    public abstract Boolean isUserNodeContains(String userId);

    /**
     * 获取所有节点信息
     *
     * @return
     */
    public abstract ConcurrentHashMap<Integer, Node> getNodeInfos();

    /**
     * 获取janus节点信息
     *
     * @param nodeId
     * @return
     */
    public abstract Node getNodeInfo(int nodeId);

    /**
     * 添加janus节点信息
     *  @param nodeId
     * @param node
     * @return
     */
    public abstract boolean putNodeInfo(int nodeId, Node node);


    /**
     * 更新janus节点信息
     *
     * @param nodeId
     * @param node
     */
    public abstract boolean updateNodeInfo(int nodeId, Node node);

    /**
     * 移除janus节点信息
     *
     * @param nodeId
     */
    public abstract boolean removeNodeInfo(int nodeId);


    /**
     * 获取可使用janus节点
     *
     * @param roomId
     * @return
     */
    public int getFreeNode(String roomId) throws Exception {
        int node = -1;
        switch (getLoadDistributionStrategy()) {
            case LoadDistributionStrategy.ROOM_FIRST:
                node = getNodeByRoomFirst(roomId);
                janusLogUtil.log("roomId:"+roomId+"根据房间优先原则获取janus节点:"+node,this.getClass(),JanusLogUtil.TRACE);
                if (node == -1) {
                    node = getNodeByFreeFirst();
                    janusLogUtil.log("roomId:"+roomId+"根据空闲优先原则获取janus节点:"+node,this.getClass(),JanusLogUtil.TRACE);
                }
                break;
            case LoadDistributionStrategy.FREE_FIRST:
                node = getNodeByFreeFirst();
                janusLogUtil.log("roomId:"+roomId+"根据空闲优先原则获取janus节点:"+node,this.getClass(),JanusLogUtil.TRACE);
                break;
            default:
                break;
        }
        if (node == -1) {
            throw new Exception("janus服务器繁忙");
        }
        putRoomNodeId(roomId, node);
        return node;
    }

    /**
     * 查询房间是否在某一个janus节点
     *
     * @param roomId
     * @return
     */
    public abstract boolean isRoomNodeIdContainsKey(String roomId);

    /**
     * 获取房间所在janus节点node
     *
     * @param roomId
     * @return
     */
    public abstract int getRoomNodeId(String roomId);

    /**
     * 更新房间所在janus节点node
     *
     * @param roomId
     * @return
     */
    public abstract void putRoomNodeId(String roomId, int nodeId);

    /**
     * 删除房间所在janus节点node信息
     *
     * @param roomId
     * @return
     */
    public abstract void removeRoomNodeId(String roomId);

    /**
     * 根据房间优先原则获取janus节点
     *
     * @param roomId
     * @return
     */
    public int getNodeByRoomFirst(String roomId) {
        int node = -1;
        if (isRoomNodeIdContainsKey(roomId)) {
            node = getRoomNodeId(roomId);
            Node n = getNodeInfo(node);
            if (n.getParticipant() >= getMaxParticipant()) {
                return -1;
            }
        }
        return node;
    }

    /**
     * 根据空闲优先原则获取janus节点
     *
     * @return
     */
    public int getNodeByFreeFirst() {
        int node = -1;
        int min = Integer.MAX_VALUE;
        for (Node n : getNodeInfos().values()) {
            if (n.getParticipant() < min && n.getParticipant() < getMaxParticipant()) {
                min = n.getParticipant();
                node = n.getNodeId();
            }
        }
        return node;
    }

    /**
     * 添加用户到某个janus节点
     *
     * @param userId
     * @param nodeId
     * @throws Exception
     */
    public int putUserToNode(String userId, int nodeId) {
        if (!isUserNodeContains(userId)) {
            String key = ""+nodeId;
            RedissLockUtil.tryLock(key, TimeUnit.SECONDS, 10, 3);
            janusLogUtil.log(Thread.currentThread().getName() + "||" + key + "获取锁", this.getClass(), JanusLogUtil.TRACE);
            try {
                Node node = getNodeInfo(nodeId);
                node.setParticipant(node.getParticipant() + 1);
                putNodeInfo(nodeId, node);
                putUserNode(userId, nodeId);
            }finally {
                RedissLockUtil.unlock(key);
                janusLogUtil.log(Thread.currentThread().getName() + "||" + key + "释放锁", this.getClass(), JanusLogUtil.TRACE);
            }
            janusLogUtil.log("添加用户:"+nodeId + "到janus节点:"+nodeId, this.getClass(), JanusLogUtil.TRACE);
        }
        return nodeId;
    }

    /**
     * 查询用户是否再某一个房间
     *
     * @param userId
     * @return
     */
    public abstract boolean isUserRoomContainsKey(String userId);

    /**
     * 查询用户房间号
     *
     * @param userId
     * @return
     */
    public abstract String getUserRoom(String userId);

    /**
     * 更新用户房间号
     *
     * @param userId
     * @param roomId
     */
    public abstract void putUserRoom(String userId, String roomId);

    /**
     * 移除用户房间号
     *
     * @param userId
     */
    public abstract void removeUserRoom(String userId);


    /**
     * 查询房间是否存在
     *
     * @param roomId
     * @return
     */
    public abstract boolean isRoomContainsKey(String roomId);

    /**
     * 使用roomId 获取房间信息
     *
     * @param roomId
     * @return
     */
    public abstract Room getRoom(String roomId);

    /**
     * 更新房间信息
     *
     * @param roomId
     * @param room
     */
    public abstract void putRoom(String roomId, Room room);

    /**
     * 移除房间
     *
     * @param roomId
     */
    public abstract void removeRoom(String roomId);

    /**
     * 加入房间
     *
     * @param userId
     * @param roomId
     */
    public void joinRoom(String userId, String roomId) throws Exception {
        if(!isUserNodeContains(userId) || !isUserRoomContainsKey(userId)){
            putUserToNode(userId, getFreeNode(roomId));
            putUserRoom(userId, roomId);
        }
        Participant participant = new Participant();
        participant.setDisplay(userId);
        participant.setNode(getUserNode(userId));
        janusLogUtil.log("房间roomId:"+userId+"加入参与者:"+participant,this.getClass(),JanusLogUtil.TRACE);
        Room room = getAVRoomByRoomId(roomId);
        room.addParticipant(participant);
        updateAVRoom(roomId, room);
    }

    public void updateParticipant(String userId, String roomId, long session_id, long handle_id, Long publisher_id, String targetUserId) {
        Room room = getAVRoomByRoomId(roomId);
        Participant participant = room.getParticipantHashMap().get(userId);
        janusLogUtil.log("根据userId:"+userId+"获取信息:"+participant,this.getClass(),JanusLogUtil.TRACE);
        if(participant!=null) {
            participant.setSession_id(session_id);
            if (userId.equals(targetUserId)) {
                participant.setHandle_id(handle_id);
                participant.setPublisher_id(publisher_id);
            } else {
                HashMap<String, Long> handleIds = participant.getHandleIds();
                handleIds.put(targetUserId, handle_id);
                participant.setHandleIds(handleIds);
            }
            janusLogUtil.log("房间roomId:" + userId + "更新参与者:" + participant, this.getClass(), JanusLogUtil.TRACE);
            room.addParticipant(participant);
            updateAVRoom(roomId, room);
        }
    }

    public void updateParticipant(String userId, Participant participant) {
        String roomId = getUserRoom(userId);
        String key = String.valueOf(roomId);
        RedissLockUtil.tryLock(key, TimeUnit.SECONDS, 10, 3);
        janusLogUtil.log(Thread.currentThread().getName() + "||" + key + "获取锁", this.getClass(), JanusLogUtil.TRACE);
        try {
            Room room = getAVRoomByRoomId(roomId);
            janusLogUtil.log("房间roomId:" + userId + "更新参与者:" + participant, this.getClass(), JanusLogUtil.TRACE);
            room.addParticipant(participant);
            updateAVRoom(getUserRoom(userId), room);
        } finally {
            RedissLockUtil.unlock(key);
            janusLogUtil.log(Thread.currentThread().getName() + "||" + key + "释放锁", this.getClass(), JanusLogUtil.TRACE);
        }

    }

    /**
     * 离开房间
     *
     * @param userId
     */
    public void leaveRoom(String userId) {
        if (isUserRoomContainsKey(userId)) {
            String roomId = getUserRoom(userId);
            String key = roomId;
            RedissLockUtil.tryLock(key, TimeUnit.SECONDS, 10, 3);
            janusLogUtil.log(Thread.currentThread().getName() + "||" + key + "获取锁", this.getClass(), JanusLogUtil.TRACE);
            try {
                removeUserRoom(userId);
                janusLogUtil.log("用户:" + userId + "离开房间:" + roomId, this.getClass(), JanusLogUtil.TRACE);
                Room room = getAVRoomByRoomId(roomId);
                janusLogUtil.log("房间roomId:" + roomId + "移除参与者:" + userId, this.getClass(), JanusLogUtil.TRACE);
                room.removeParticipant(userId);
                if (room.getParticipantList().size() == 0) {
                    removeRoomNodeId(roomId);
                    updateAVRoom(roomId, null);
                    janusLogUtil.log("房间roomId:" + roomId + "参与人数为0,销毁房间.", this.getClass(), JanusLogUtil.TRACE);
                } else {
                    updateAVRoom(roomId, room);
                    janusLogUtil.log("更新房间roomId:" + roomId + "信息:" + room, this.getClass(), JanusLogUtil.TRACE);
                }
            }finally {
                RedissLockUtil.unlock(key);
                janusLogUtil.log(Thread.currentThread().getName() + "||" + key + "释放锁", this.getClass(), JanusLogUtil.TRACE);
            }
        }
    }
    /**
     * 通知房间内所有用户
     *
     * @param userId
     */
    public void notifyAllParticipantLeaving(String userId) {
        Room room = getAVRoomByUserId(userId);
        Participant user = room.getParticipantHashMap().get(userId);
        List<Participant> remoteParticipant = room.getParticipantList();
        for (Participant participant : remoteParticipant) {
            if(userId.equals(participant.getDisplay())){
                //不通知自己
                continue;
            }
            Event remoteEvent = new Event();
            remoteEvent.setSender(participant.getHandle_id());
            remoteEvent.setSession_id(participant.getSession_id());
            Plugindata plugindata = new Plugindata();
            Data data = new Data();
            data.setLeaving(user.getDisplay());
            janusLogUtil.log("通知用户:"+participant.getDisplay()+" "+userId+"离开",this.getClass(),JanusLogUtil.TRACE);
            plugindata.setData(data);
            remoteEvent.setPlugindata(plugindata);
            imSender.sendEvent(participant.getDisplay(), remoteEvent);
            webSocketSender.sendEvent(participant.getDisplay(), remoteEvent);
        }
    }
    /**
     * 通知房间内其他节点的用户
     * @param userId
     */
    public void notifyRemoteParticipantJoining(String userId) {
        Room room = getAVRoomByUserId(userId);
        Participant user = room.getParticipantHashMap().get(userId);
        List<Participant> remoteParticipant = room.oldGetRemoteParticipant(getUserNode(userId));
        for (Participant participant : remoteParticipant) {
            Event remoteEvent = new Event();
            remoteEvent.setSender(participant.getHandle_id());
            remoteEvent.setSession_id(participant.getSession_id());
            Plugindata plugindata = new Plugindata();
            Data data = new Data();
            Publisher publisher = new Publisher();
            publisher.setDisplay(userId);
            publisher.setId(user.getPublisher_id());
            publisher.setRemote(true);
            List<Publisher> publishers = new ArrayList<>();
            publishers.add(publisher);
            data.setPublishers(publishers);
            janusLogUtil.log("通知用户:"+participant.getDisplay()+" "+userId+"加入",this.getClass(),JanusLogUtil.TRACE);
            plugindata.setData(data);
            remoteEvent.setPlugindata(plugindata);
            imSender.sendEvent(participant.getDisplay(), remoteEvent);
            webSocketSender.sendEvent(participant.getDisplay(), remoteEvent);
        }
    }

    /**
     * 把用户从节点移除
     *
     * @param userId
     */
    public void removeUserFromNode(String userId) {
        if (isUserNodeContains(userId)) {
            int nodeId = getUserNode(userId);
            String key = ""+nodeId;
            RedissLockUtil.tryLock(key, TimeUnit.SECONDS, 10, 3);
            janusLogUtil.log(Thread.currentThread().getName() + "||" + key + "获取锁", this.getClass(), JanusLogUtil.TRACE);
            try {
                Node node = getNodeInfo(nodeId);
                node.setParticipant(Math.max(node.getParticipant() - 1, 0));
                putNodeInfo(nodeId, node);
                removeUserNode(userId);
            }
            finally {
                RedissLockUtil.unlock(key);
                janusLogUtil.log(Thread.currentThread().getName() + "||" + key + "释放锁", this.getClass(), JanusLogUtil.TRACE);
            }
            janusLogUtil.log("把用户:"+userId + "从节点:"+nodeId+"移除", this.getClass(), JanusLogUtil.TRACE);
        }
    }

    /**
     * 把用户从节点移除
     *
     * @param userId
     */
    public abstract void removeUserNode(String userId);

    /**
     * 获取用户当前所在节点
     *
     * @param userId
     * @return
     */
    public abstract int getUserNode(String userId);

    /**
     * 添加用户到某节点
     *
     * @param userId
     */
    public abstract void putUserNode(String userId, int nodeId);

    /**
     * 根据roomId获取房间信息
     *
     * @param roomId
     * @return
     */
    public Room getAVRoomByRoomId(String roomId) {
        Room room = getRoom(roomId);
        if (room == null) {
            room = new Room();
        }
        janusLogUtil.log("根据roomId:"+roomId+"获取房间信息:"+room.toString(),this.getClass(),JanusLogUtil.TRACE);
        return room;
    }
    /**
     * 根据用户id获取用户信息
     *
     * @param userId
     * @return
     */
    public Participant getParticipantByUserId(String userId) {
        Participant participant = Optional.ofNullable(getAVRoomByUserId(userId))
                .map(Room::getParticipantHashMap)
                .map(i -> i.get(userId))
                .orElse(null);
        janusLogUtil.log("根据用户id:" + userId + "获取用户信息:" + participant, this.getClass(), JanusLogUtil.TRACE);
        return participant;
    }
    /**
     * 根据用户id获取房间信息
     *
     * @param userId
     * @return
     */
    public Room getAVRoomByUserId(String userId) {
        String roomId = getUserRoom(userId);
        if (roomId == null) {
            return new Room();
        }
        return getAVRoomByRoomId(roomId);
    }

    /**
     * 更新房间信息
     *
     * @param roomId
     * @param room
     */
    public void updateAVRoom(String roomId, Room room) {
        if (room == null) {
            removeRoom(roomId);
        } else {
            putRoom(roomId, room);
        }
    }

    /**
     * 释放端口
     *
     * @param port
     */
    public abstract void removePort(int port);

    /**
     * 查询端口是否被占用
     *
     * @param port
     */
    public abstract boolean isPortContains(int port);

    /**
     * 添加使用端口
     *
     * @param port
     */
    public abstract void addPort(int port);

    /**
     * 获取可用端口
     *
     * @return
     */
    public int getPort() {
        Random random = new Random();
        int port;
        do {
            port = random.nextInt(janusConfig.getMax_port() - janusConfig.getMin_port() + 1) + janusConfig.getMin_port();
        }
        while (isPortContains(port));
        addPort(port);
        return port;
    }
}
